package com.shinbada.modules.sys.service;

import com.shinbada.common.ResultCode;
import com.shinbada.common.tree.TreeLevelUtil;
import com.shinbada.core.service.CompanyClearService;
import com.shinbada.core.service.CreateCompanyAfterInitService;
import com.shinbada.core.service.TreeService;
import com.shinbada.exception.ServiceException;
import com.shinbada.modules.sys.company.CompanyRegister;
import com.shinbada.modules.sys.entity.Office;
import com.shinbada.modules.sys.entity.Role;
import com.shinbada.modules.sys.entity.SysSetting;
import com.shinbada.modules.sys.entity.User;
import com.shinbada.modules.sys.mapper.OfficeMapper;
import com.shinbada.modules.sys.reference.OfficeReferenceService;
import com.shinbada.modules.sys.utils.UserUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Comparator;
import java.util.List;

/**
 * 机构Service
 *
 * @author initcap
 * @version 2017-05-16
 */
@Slf4j
@Service
@Transactional(readOnly = true)
public class OfficeService extends TreeService<OfficeMapper, Office> {

    @Autowired
    private RoleService roleService;
    @Autowired
    private UserService userService;
    @Autowired
    private SysSettingService settingService;
    @Autowired
    private DictTypeService dictTypeService;
    @Autowired
    private List<CompanyClearService> clearServices;
    @Autowired
    private List<OfficeReferenceService> officeReferenceServiceList;
    @Autowired
    private List<CreateCompanyAfterInitService> createCompanyAfterInitServices;

    public List<Office> findAll() {
        return UserUtils.getOfficeList();
    }

    public List<Office> findList(Boolean isAll) {
        if (isAll != null && isAll) {
            return UserUtils.getOfficeAllList();
        } else {
            return UserUtils.getOfficeList();
        }
    }

    @Override
    @Transactional(readOnly = true)
    public List<Office> findList(Office office) {
        office.setParentIds(office.getParentIds() + "%");
        return mapper.findByParentIdsLike(office);
    }

    @Transactional(readOnly = true)
    public Office getByCode(String code) {
        return mapper.getByCode(code);
    }

    @Override
    public List<Office> getChildren(String parentId) {
        User user = UserUtils.getUser();
        if (user.isAdmin()) {
            return mapper.getChildren(parentId);
        } else {
            return mapper.getChildrenByCompanyId(parentId, user.getCompany().getId());
        }
    }

    @Override
    @Transactional(readOnly = false)
    public void save(Office office) {
        saveBeforeCheck(office);

        // 获取排序号，最末节点排序号+30
        if (StringUtils.isBlank(office.getId())) {
            Office searchOffice = new Office();
            searchOffice.setParent(new Office(office.getParentId()));
            List<Office> sourcelist = findList(searchOffice);
            sourcelist.sort(Comparator.comparing(Office::getSort));
            if (CollectionUtils.isNotEmpty(sourcelist)) {
                office.setSort(sourcelist.get(sourcelist.size() - 1).getSort() + 30);
            }
        }

        super.save(office);
    }

    @Override
    @Transactional(readOnly = false)
    public void delete(Office office) {
        officeReferenceServiceList.forEach(reference -> {
            if (reference.isReference(office.getId()) && UserUtils.keepReference()) {
                throw new ServiceException(ResultCode.OFFICE_REFERENCE_CAN_NOT_DELETE, ",引用者: " + reference.getName());
            } else if (reference.isReference(office.getId()) && !UserUtils.keepReference()) {
                reference.deleteReference(office.getId());
            }
        });
        // 只有超级管理员才能进行删除公司，部门所有用户都可以进行删除
        if (!UserUtils.getUser().isAdmin() && isCompany(office)) {
            throw new ServiceException(ResultCode.COMPANY_MUST_ADMIN_DELETE);
        }
        super.delete(office);
        if (isCompany(office)) {
            // 只有超级管理员能够进行机构的清理
            if (!UserUtils.getUser().isAdmin()) {
                throw new ServiceException(ResultCode.ONLY_ADMIN_CLEAR_COMPANY);
            }
            if (UserUtils.DEFAULT_COMPANY_ID.equals(office.getId())) {
                throw new ServiceException(ResultCode.DEFAULT_COMPANY_CAN_NOT_CLEAR);
            }
            clearServices.forEach(companyClearService -> companyClearService.companyClear(office.getId()));
        }
    }

    @Transactional(readOnly = false)
    public void register(CompanyRegister register) {
        Office office = register.toOffice();
        // 注册机构
        save(office);
        // 执行所有事件
        createCompanyAfterInitServices.forEach(init -> init.execute(office.getId()));

        // 创建角色
        Role role = register.toRole(office.getId());
        roleService.registeRole(role);
        log.info("【创建机构】后续添加角色信息 : {}", role);

        // 创建管理员
        User user = register.toUser(office.getId(), role.getId());
        userService.saveUser(user);
        log.info("【创建机构】后续创建用户信息 : {}", user);

        // 创建系统配置信息
        SysSetting setting = register.toSetting(office.getId());
        settingService.init(setting);
        log.info("【创建机构】后续创建配置信息 : {}", setting);

        // 复制字典信息
        dictTypeService.copyDictValueByCompanyId(register.getSourceDictCompanyId(), office.getId());
    }

    private boolean isCompany(Office office) {
        Office dbOffice = get(office.getId());
        if (dbOffice != null) {
            return TreeLevelUtil.ROOT.equals(dbOffice.getParent().getId());
        }
        return false;
    }

    private void saveBeforeCheck(Office office) {
        if (currentLevelNameExist(office.getId(), office.getParent(), office.getName())) {
            throw new ServiceException(ResultCode.OFFICE_CURRENT_LEVEL_NAME_EXIST);
        }
        // 判断需要填写上级机构的情况
        boolean parentMustHave =
                // 新增情况
                StringUtils.isBlank(office.getId())
                        // 非超级管理员
                        && !UserUtils.getUser().isAdmin()
                        // 没有指定上级机构
                        && (office.getParent() == null || StringUtils.isBlank(office.getParent().getId()));

        if (parentMustHave) {
            throw new ServiceException(ResultCode.PARENT_OFFICE_MUST_HAVE);
        }
    }

    private boolean currentLevelNameExist(String id, Office parent, String name) {
        String parentId = TreeLevelUtil.ROOT;
        if (parent != null && StringUtils.isNotBlank(parent.getId())) {
            parentId = parent.getId();
        }
        return mapper.countCurrentLevelName(id, parentId, name) > 0;
    }

}
